/*
 * movegen.c
 *
 *  Created on: Apr 6, 2013
 *      Author: locpx
 */
#include "defines.h"
#include "extglobals.h"
#include "protos.h"
#include "move.h"

unsigned int movegen(unsigned int index)
{
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	// This is tuongky's pseudo-legal bitboard move generator,
	// using magic multiplication instead of rotated bitboards.
	// There is no check if a move leaves the king in check
	// The first free location in moveBuffer[] is supplied in index,
	// and the new first free location is returned
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

	unsigned int from, to;
	BITBOARD tempPiece, tempMove;
	BITBOARD targetBitBoard;
	MOVE move;

	clear(&move);

	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	// Black to move
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	if (board.nextMove)
	{
		// we cannot capture one of our own pieces!
		targetBitBoard = notBitBoard(board.blackPieces);

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black horses
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		setPiec(&move, BLACK_HORSE);
		tempPiece = board.blackHorses;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][3]);

			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black elephants
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_ELEPHANT);
		tempPiece = board.blackElephants;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);
			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][3]);
			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black advisors
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_ADVISOR);
		tempPiece = board.blackAdvisors;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(ADVISOR_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black king
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_KING);
		tempPiece = board.blackKing;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(KING_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black pawns
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_PAWN);
		tempPiece = board.blackPawns;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(BLACK_PAWN_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black rooks
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD rookAttacks, rookRightAttacks, rookTopAttacks, rookLeftAttacks, rookBottomAttacks;
		clear(&move);
		setPiec(&move, BLACK_ROOK);
		tempPiece = board.blackRooks;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			// We do this because the first piece will stop the rook moving to the right.
			rookRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(rookRightAttacks))
				rookRightAttacks = ATTACKS_RIGHT[findFirstOneInBitBoard(rookRightAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			rookRightAttacks = xorTwoBitBoards(rookRightAttacks, ATTACKS_RIGHT[from]);

			// We do this because the first piece will stop the rook moving on the top.
			rookTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(rookTopAttacks))
				rookTopAttacks = ATTACKS_TOP[findFirstOneInBitBoard(rookTopAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_TOP[from]
			rookTopAttacks = xorTwoBitBoards(rookTopAttacks, ATTACKS_TOP[from]);

			// We do this because the first piece will stop the rook moving to the left.
			rookLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(rookLeftAttacks))
				rookLeftAttacks = ATTACKS_LEFT[findLastOneInBitBoard(rookLeftAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			rookLeftAttacks = xorTwoBitBoards(rookLeftAttacks, ATTACKS_LEFT[from]);

			// We do this because the first piece will stop the rook moving on the bottom.
			rookBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(rookBottomAttacks))
				rookBottomAttacks = ATTACKS_BOTTOM[findLastOneInBitBoard(rookBottomAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			rookBottomAttacks = xorTwoBitBoards(rookBottomAttacks, ATTACKS_BOTTOM[from]);

			rookAttacks = orTwoBitBoards(rookRightAttacks, rookTopAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookLeftAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookBottomAttacks);

			tempMove = andTwoBitBoards(rookAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black cannons
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD cannonAttacks, cannonRightAttacks, cannonTopAttacks, cannonLeftAttacks, cannonBottomAttacks;
		BITBOARD rightTempBB, topTempBB, leftTempBB, bottomTempBB;
		clear(&move);
		setPiec(&move, BLACK_CANNON);
		tempPiece = board.blackCannons;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&rightTempBB);
			clearBitBoard(&topTempBB);
			clearBitBoard(&leftTempBB);
			clearBitBoard(&bottomTempBB);

			// We do this because the first piece will stop the rook moving to the right.
			cannonRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(cannonRightAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonRightAttacks);
				cannonRightAttacks = ATTACKS_RIGHT[firstOne];
				cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, BITBOARDSET[firstOne]);

				rightTempBB = andTwoBitBoards(ATTACKS_RIGHT[firstOne], board.whitePieces);
				if (!isAllZeroBit(rightTempBB))
					rightTempBB = BITBOARDSET[findFirstOneInBitBoard(rightTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			cannonRightAttacks = xorTwoBitBoards(cannonRightAttacks, ATTACKS_RIGHT[from]);
			// Eat if possible
			cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, rightTempBB);


			// We do this because the first piece will stop the cannon moving on the top.
			cannonTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(cannonTopAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonTopAttacks);
				cannonTopAttacks = ATTACKS_TOP[firstOne];
				cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, BITBOARDSET[firstOne]);

				topTempBB = andTwoBitBoards(ATTACKS_TOP[firstOne], board.whitePieces);
				if (!isAllZeroBit(topTempBB))
					topTempBB = BITBOARDSET[findFirstOneInBitBoard(topTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_TOP[from]
			cannonTopAttacks = xorTwoBitBoards(cannonTopAttacks, ATTACKS_TOP[from]);
			// Eat if possible
			cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, topTempBB);


			// We do this because the first piece will stop the cannon moving to the left.
			cannonLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(cannonLeftAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonLeftAttacks);
				cannonLeftAttacks = ATTACKS_LEFT[lastOne];
				cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, BITBOARDSET[lastOne]);

				leftTempBB = andTwoBitBoards(ATTACKS_LEFT[lastOne], board.whitePieces);
				if (!isAllZeroBit(leftTempBB))
					leftTempBB = BITBOARDSET[findLastOneInBitBoard(leftTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			cannonLeftAttacks = xorTwoBitBoards(cannonLeftAttacks, ATTACKS_LEFT[from]);
			// Eat if possible
			cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, leftTempBB);


			// We do this because the first piece will stop the cannon moving on the bottom.
			cannonBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(cannonBottomAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonBottomAttacks);
				cannonBottomAttacks = ATTACKS_BOTTOM[lastOne];
				cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, BITBOARDSET[lastOne]);

				bottomTempBB = andTwoBitBoards(ATTACKS_BOTTOM[lastOne], board.whitePieces);
				if (!isAllZeroBit(bottomTempBB))
					bottomTempBB = BITBOARDSET[findLastOneInBitBoard(bottomTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			cannonBottomAttacks = xorTwoBitBoards(cannonBottomAttacks, ATTACKS_BOTTOM[from]);
			// Eat if possible
			cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, bottomTempBB);

			cannonAttacks = orTwoBitBoards(cannonRightAttacks, cannonTopAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonLeftAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonBottomAttacks);

			tempMove = andTwoBitBoards(cannonAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}
	}
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	// White to move
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	else
	{
		// we cannot capture one of our own pieces!
		targetBitBoard = notBitBoard(board.whitePieces);

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White horses
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		setPiec(&move, WHITE_HORSE);
		tempPiece = board.whiteHorses;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][3]);

			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White elephants
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_ELEPHANT);
		tempPiece = board.whiteElephants;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);
			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][3]);
			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White advisors
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_ADVISOR);
		tempPiece = board.whiteAdvisors;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(ADVISOR_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// white king
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_KING);
		tempPiece = board.whiteKing;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(KING_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White pawns
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_PAWN);
		tempPiece = board.whitePawns;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(WHITE_PAWN_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White rooks
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD rookAttacks, rookRightAttacks, rookTopAttacks, rookLeftAttacks, rookBottomAttacks;
		clear(&move);
		setPiec(&move, WHITE_ROOK);
		tempPiece = board.whiteRooks;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			// We do this because the first piece will stop the rook moving to the right.
			rookRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(rookRightAttacks))
				rookRightAttacks = ATTACKS_RIGHT[findFirstOneInBitBoard(rookRightAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			rookRightAttacks = xorTwoBitBoards(rookRightAttacks, ATTACKS_RIGHT[from]);

			// We do this because the first piece will stop the rook moving on the top.
			rookTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(rookTopAttacks))
				rookTopAttacks = ATTACKS_TOP[findFirstOneInBitBoard(rookTopAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_TOP[from]
			rookTopAttacks = xorTwoBitBoards(rookTopAttacks, ATTACKS_TOP[from]);

			// We do this because the first piece will stop the rook moving to the left.
			rookLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(rookLeftAttacks))
				rookLeftAttacks = ATTACKS_LEFT[findLastOneInBitBoard(rookLeftAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			rookLeftAttacks = xorTwoBitBoards(rookLeftAttacks, ATTACKS_LEFT[from]);

			// We do this because the first piece will stop the rook moving on the bottom.
			rookBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(rookBottomAttacks))
				rookBottomAttacks = ATTACKS_BOTTOM[findLastOneInBitBoard(rookBottomAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			rookBottomAttacks = xorTwoBitBoards(rookBottomAttacks, ATTACKS_BOTTOM[from]);

			rookAttacks = orTwoBitBoards(rookRightAttacks, rookTopAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookLeftAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookBottomAttacks);

			tempMove = andTwoBitBoards(rookAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White cannons
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD cannonAttacks, cannonRightAttacks, cannonTopAttacks, cannonLeftAttacks, cannonBottomAttacks;
		BITBOARD rightTempBB, topTempBB, leftTempBB, bottomTempBB;
		clear(&move);
		setPiec(&move, WHITE_CANNON);
		tempPiece = board.whiteCannons;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&rightTempBB);
			clearBitBoard(&topTempBB);
			clearBitBoard(&leftTempBB);
			clearBitBoard(&bottomTempBB);

			// We do this because the first piece will stop the rook moving to the right.
			cannonRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(cannonRightAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonRightAttacks);
				cannonRightAttacks = ATTACKS_RIGHT[firstOne];
				cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, BITBOARDSET[firstOne]);

				rightTempBB = andTwoBitBoards(ATTACKS_RIGHT[firstOne], board.blackPieces);
				if (!isAllZeroBit(rightTempBB))
					rightTempBB = BITBOARDSET[findFirstOneInBitBoard(rightTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			cannonRightAttacks = xorTwoBitBoards(cannonRightAttacks, ATTACKS_RIGHT[from]);
			// Eat if possible
			cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, rightTempBB);


			// We do this because the first piece will stop the cannon moving on the top.
			cannonTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(cannonTopAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonTopAttacks);
				cannonTopAttacks = ATTACKS_TOP[firstOne];
				cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, BITBOARDSET[firstOne]);

				topTempBB = andTwoBitBoards(ATTACKS_TOP[firstOne], board.blackPieces);
				if (!isAllZeroBit(topTempBB))
					topTempBB = BITBOARDSET[findFirstOneInBitBoard(topTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_TOP[from]
			cannonTopAttacks = xorTwoBitBoards(cannonTopAttacks, ATTACKS_TOP[from]);
			// Eat if possible
			cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, topTempBB);


			// We do this because the first piece will stop the cannon moving to the left.
			cannonLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(cannonLeftAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonLeftAttacks);
				cannonLeftAttacks = ATTACKS_LEFT[lastOne];
				cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, BITBOARDSET[lastOne]);

				leftTempBB = andTwoBitBoards(ATTACKS_LEFT[lastOne], board.blackPieces);
				if (!isAllZeroBit(leftTempBB))
					leftTempBB = BITBOARDSET[findLastOneInBitBoard(leftTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			cannonLeftAttacks = xorTwoBitBoards(cannonLeftAttacks, ATTACKS_LEFT[from]);
			// Eat if possible
			cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, leftTempBB);


			// We do this because the first piece will stop the cannon moving on the bottom.
			cannonBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(cannonBottomAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonBottomAttacks);
				cannonBottomAttacks = ATTACKS_BOTTOM[lastOne];
				cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, BITBOARDSET[lastOne]);

				bottomTempBB = andTwoBitBoards(ATTACKS_BOTTOM[lastOne], board.blackPieces);
				if (!isAllZeroBit(bottomTempBB))
					bottomTempBB = BITBOARDSET[findLastOneInBitBoard(bottomTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			cannonBottomAttacks = xorTwoBitBoards(cannonBottomAttacks, ATTACKS_BOTTOM[from]);
			// Eat if possible
			cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, bottomTempBB);

			cannonAttacks = orTwoBitBoards(cannonRightAttacks, cannonTopAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonLeftAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonBottomAttacks);

			tempMove = andTwoBitBoards(cannonAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}
	}

	return index;
}
